#include "FbxAnimationTransform.h"

namespace GC
{
	GC::FbxAnimationTransform::FbxAnimationTransform(	const FbxNode* a_node, 
																		const GC::FbxAnimationChannel* a_translation,
																		const GC::FbxAnimationChannel* a_rotation,
																		const GC::FbxAnimationChannel* a_scale)
	{
		if (ConverterApp::GetSettings()->IsUsingDualQuaternions() )
		{
			CalculateDQTransform( a_node, a_translation, a_rotation, a_scale );
		}
		else
		{
			CalculateMat4x4Transform( a_node, a_translation, a_rotation, a_scale);
		}
	}
	/* Public GET functions */
	/// <summary>
	/// Gets the transform.
	/// </summary>
	/// <returns></returns>
	const GC::FbxAnimationTransformKey GC::FbxAnimationTransform::GetTransform() const
	{
		return m_transform;
	}
	const GC::FbxAnimationTransformKey GC::FbxAnimationTransform::GetScale() const
	{
		return m_scale;
	}

	const size_t GC::FbxAnimationTransform::GetTransformSize() const
	{
		return m_transform.size();
	}
	/// <summary>
	/// Will be 0 if using dual quaternions
	/// </summary>
	/// <returns></returns>
	const size_t GC::FbxAnimationTransform::GetScaleSize() const
	{
		return m_scale.size();
	}
	
	/* Private functions*/
	void GC::FbxAnimationTransform::CalculateDQTransform(
									const FbxNode* a_node, 
									const GC::FbxAnimationChannel* a_translation, 
									const GC::FbxAnimationChannel* a_rotation,
									const GC::FbxAnimationChannel* a_scale)
	{
		//Check if a_translation OR rotation exists
		if (a_translation->IsValid() || a_rotation->IsValid() )
		{
			const int f_animationLength = GetAnimationLength(2, a_translation, a_rotation);
			
			//Vectors start with LclTranslation value so it doesn't start at 0.0
			//example: z-rotation: 90 degrees and never animates z-value, it would have been 0 if not base value!
			FbxVector4 f_translation = a_node->LclTranslation.Get();
			FbxVector4 f_rotation = a_node->LclRotation.Get();

			for (int i = 0; i < f_animationLength; ++i)
			{			
				if (a_translation->HasValueAtFrame( i ) || a_rotation->HasValueAtFrame( i ) )
				{
					a_translation->GetValueAtFrame( i, f_translation);
					a_rotation->GetValueAtFrame(i, f_rotation);
					//Gets deleted in destructor
					VectorConstDouble f_transform = FbxHelper::GetDQorMatrix4x4();

					FbxDualQuaternion f_transformDQ( FbxHelper::GetQuaternion(f_rotation, true) , f_translation );

					FbxHelper::SetDQorMat4x4FromDQ(f_transformDQ , f_transform );

					m_transform.insert( std::make_pair( i, f_transform ) );
				}
			}
		}
		//Do scale stuff! (copy the std::map)
		if (a_scale->IsValid())
		{
			const int f_animationLength = GetAnimationLength(1, a_scale);

			FbxVector4 f_scale = a_node->LclScaling.Get();

			for (int i = 0; i < f_animationLength; ++i)
			{
				if (a_scale->HasValueAtFrame(i) )
				{
					a_scale->GetValueAtFrame(i, f_scale);
					VectorConstDouble f_scaleValue = VectorConstDouble();	
					f_scaleValue.reserve(3);
					f_scaleValue.push_back(f_scale[0]);
					f_scaleValue.push_back(f_scale[1]);
					f_scaleValue.push_back(f_scale[2]);
					
					m_scale.insert( std::make_pair( i, f_scaleValue ) );
				}
			}
		}	
	}

	void GC::FbxAnimationTransform::CalculateMat4x4Transform(
									const FbxNode* a_node, 
									const GC::FbxAnimationChannel* a_translation, 
									const GC::FbxAnimationChannel* a_rotation,
									const GC::FbxAnimationChannel* a_scale)
	{
		ConverterApp::LogMessage(L"FAILED: CalculateMat4x4Transform FUNCTION NOT IMPLEMENTED");
	}

	const int GC::FbxAnimationTransform::GetAnimationLength(const int a_paramCount, ...) const
	{
		va_list vl;
		va_start(vl, a_paramCount);		

		int f_length = -1;

		for (int i = 0; i < a_paramCount; ++i)
		{
			GC::FbxAnimationChannel* f_channel = va_arg(vl, GC::FbxAnimationChannel*);

			const int f_temp = f_channel->GetAnimationLength();

			if (f_temp > f_length)
			{
				f_length = f_temp;
			}
		}

		va_end(vl);

		return f_length;
	}
}